#ifndef tlg_h_2l34k3564mrnylkjrhtiuhtie845hw3k4j5ntrl
#define tlg_h_2l34k3564mrnylkjrhtiuhtie845hw3k4j5ntrl

unsigned char n = 0, // Pocet uzlu -  ze zadani vzdy n>=5
              t = 0, // Trivialni reseni - horni pulka maximalniho stupne grafu
              k = 0; // Prumerny stupen uzlu n>=k>=3, radove vsak jednotky
unsigned char** M;   // Jednoduchy, neorientovany, neohodnoceny, souvisly graf (matice incidence)

int my_rank = 0;   // cislo procesoru
int cpu_count;     // pocet procesoru
MPI_Status status; // status prijate zpravy MPI


void printMatrix();
void readMatrix(char* filename);
int permutationThickness(const unsigned char p[], const int depth, const int result);
std::string permutationToString(const unsigned char p[], const int size = n);


#include <iostream>
#include <fstream>  //reading input file
#include <sstream>
#include <string>

#include "log.h"




/**
 * Vypsani matice na standardni vystup
 */
void printMatrix() {
    logstream << "n: " << (int)n << "t: " << (int)t << "k: " << (int)k << std::endl;

    int i, j;
    for (i = 0; i < n; ++i) {
        for (j = 0; j < n; ++j) {
            logstream << (M[i][j] ? "1" : "0");
        }
        logstream << std::endl;
    }
    logstream << std::endl;
	log(LOG_INPUT);
}

/**
 * Nacteni matice ze standardniho vstupu
 */
void readMatrix(char* filename) {
	// Init
	std::string line; // nacteny radek vstupu
    int i, j, tmp;    // indexy a promenna na pocitani stupne uzlu
	
	// Open file 
	std::ifstream testfile(filename);
    if (!testfile.is_open()) {
        testfile.close();
        n = 0;
        return;
    }
	
	// Read matrix size 'n'
	int tmp_int; // načte se do intu a pak přetypuje na char, aby umožnilo načítat vícečíslicová čísla
    testfile >> tmp_int;
	n = (unsigned char)tmp_int;
    getline(testfile, line); // read emty line
	
	// Create matrix lines
    M = new unsigned char*[n];
	
	// Pres vsechny radky, pres vsechny sloupecky, vyplnime matici a napocitame jeji vlastnosti.
    for (i = 0; i < n; ++i) {
        getline(testfile, line);
        M[i] = new unsigned char[n];
        tmp = 0;
        for (j = 0; j < n; j++) { // Tady se to nesmi zkratit na j=i !!! Pri permutacich prohazujeme radky a chybely by nam tam hodnoty!
            M[i][j] = (line[j] == '1' ? 1 : 0);
            tmp += M[i][j];
        }
        t = (tmp > t ? tmp : t);
        k += tmp;
    }
    t = (t + 1) / 2; // Maximalni stupen --> Trivialni reseni
    k /= n;          // k je ted suma stupnu vsech uzlu => vydelime a ziskame prumer.
	
    testfile.close();
}


/**
 * Tloustka grafu dane permutace
 *
 * returns - napoctenou sirku permutace
 *
 * p - permutace, pole velikosti n, mapuje 0-n na zpermutovane indexy
 * depth - hloubka do ktere hledame ; depth<n ; permutace prohledame jen do urciteho bodu abychom odrizli zbytecne vetve. 
 * result - best result yet found
 */
int permutationThickness(const unsigned char p[], const int depth, const int result) {
    int ret = 0; // vysledna tloustka
    int tmp = 0; // tloustka v aktualni mezere
    int i, j, k;

    for (i = 1; i < depth; ++i) {
        tmp = 0;

        for (j = i; j < depth; ++j) {
            for (k = 0; k < i; ++k) {
				logstream << "j:" << j << ", k:" << k << ", p[j]:"<< (int)p[j] << ", p[k]:" << (int)p[k] << ", tmp:" << tmp;
				log(LOG_PERM);
                tmp += M[(int)p[j]][(int)p[k]];
            }
        }

        if (tmp >= result) {
			ret = tmp;
			break;      // Ma ukoncovat kdykoli najde tlustsi misto?
        } else if (tmp > ret) {
            ret = tmp;  // Ukladame hodnotu nejtlustsi mezery.
        }
    }
    return ret;
}


/**
 * Vypise poradi prvku permutace jako text
 * p - permutace
 * size - pocet prvku permutace
 * @return - [p][rv][ky][perm][ut][a][ce]
 */
std::string permutationToString(const unsigned char p[], const int size) {
    if (p == NULL) return "NULL!";
	std::stringstream ss;
    int i;
    for (i = 0; i < size; i++) {
        ss << '[' << (int)p[i] << ']';
    }
    return ss.str();
}


#endif //tlg_h____2l34k3564mrnylkjrhtiuhtie845hw3k4j5ntrl
